package com.automannn.practice.mybatis.dynamicProxy;

import org.apache.ibatis.mapping.MappedStatement;
import org.springframework.util.StringUtils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author chenkh
 * @time 2021/10/26 10:03
 */
public class DynamicProxyTest {

    public static void main(String[] args) {
        Map<Class, MapperProxyFactory> mapperRegistry = new HashMap<>();
        //通过这个表达方法名称，与映射关系
        Map<String, String> mappedStatements = new HashMap<>();
        mappedStatements.put("com.automannn.practice.mybatis.dynamicProxy.DynamicProxyTest$MyInterface.sayHello","  映射sayHello执行的业务逻辑");
        mapperRegistry.put(MyInterface.class,new MapperProxyFactory(MyInterface.class,mappedStatements));

        //使用
       MyInterface myInterface= (MyInterface) mapperRegistry.get(MyInterface.class).newInstance();
       myInterface.sayHello("automannn");
    }

    public static interface MyInterface {
        String sayHello(String target);
    }

    public static class MapperProxyFactory<T> {
        private final Class<T> mappedInterface;
        private final Map<Method, MethodInvoker> methodCache = new ConcurrentHashMap<>();
        private final Map<String, String> mappedStatements;

        public MapperProxyFactory(Class<T> mappedInterface, Map<String, String> mappedStatements) {
            this.mappedInterface = mappedInterface;
            this.mappedStatements = mappedStatements;
        }

        public T newInstance() {
            Class[] interfaces = new Class[]{this.mappedInterface};
            return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), interfaces, new MapperProxy(methodCache, mappedInterface, mappedStatements));
        }

    }

    public static class MapperProxy implements InvocationHandler {
        private final Map<Method, MethodInvoker> methodCache;

        private final Class mappedInterface;

        private final Map<String, String> mappedStatements;

        public MapperProxy(Map<Method, MethodInvoker> methodCache, Class mappedInterface, Map<String, String> mappedStatements) {
            this.methodCache = methodCache;
            this.mappedInterface = mappedInterface;
            this.mappedStatements = mappedStatements;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return cachedInvoker(method).invoke(proxy,method,args);
        }

        public MethodInvoker cachedInvoker(Method method) {
            MethodInvoker invoker = methodCache.get(method);
            if (invoker != null) {
                return invoker;
            }

            return methodCache.computeIfAbsent(method, method1 -> {
                return new DefaultMethodInvoker(new MappedMethod(method, mappedInterface, mappedStatements,new BusinessExecutor()));
            });
        }
    }

    public static interface MethodInvoker {
        Object invoke(Object proxy, Method method, Object[] args);
    }

    public static class DefaultMethodInvoker implements MethodInvoker {
        private final MappedMethod mappedMethod;

        public DefaultMethodInvoker(MappedMethod mappedMethod) {
            this.mappedMethod = mappedMethod;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) {
            return mappedMethod.execute(args);
        }
    }

    public static class MappedMethod {
        private final Method method;
        private final Class mappedInterface;
        //根据 method方法，获取对应的对象，可以是 文本如sql语句，可以是某个抽象接口的子类，以及其它能够遵循某种规则的对象
        private final Map<String, String> mappedRelation;
        //业务执行器
        private final BusinessExecutor businessExecutor;

        public MappedMethod(Method method, Class mappedInterface, Map<String, String> mappedRelation,BusinessExecutor businessExecutor) {
            this.method = method;
            this.mappedInterface = mappedInterface;
            this.mappedRelation = mappedRelation;
            this.businessExecutor = businessExecutor;
        }

        public Object execute(Object[] args) {
            String methodName="";
            methodName+=method.getDeclaringClass().getName();
            methodName+=".";
            methodName+=method.getName();
            String target = mappedRelation.get(methodName);
            if(!StringUtils.isEmpty(target)){
                target+="参数为:";
                target+= Arrays.asList(args).toString();
                return businessExecutor.executor(target);
            }
            return null;
        }
    }

    public static class BusinessExecutor{

        Object executor(Object target){
            if (target instanceof String){
                System.out.println("业务执行器,执行对象:"+target);
            }
            return "success";
        }
    }
}
